拆开 Multica 的源码,看看 Agent 看板到底怎么跑的
极客工具 2026年6月14日 09:56
上篇写了 Multica 的产品体验,自托管部署后跑了几个真实 Issue。体验下来感觉不错——Agent 在评论区主动汇报进度,Issue 状态自动流转,比 tmux 分屏加复制粘贴 prompt 好太多。
但体验好是一回事,适不适合长期用是另一回事。我现在的 AI 助手栈是 OpenClaw,日常记忆、生活管理、多渠道通信都在上面跑。要引入 Multica,得先搞清楚它底层到底怎么跑的、能不能跟 OpenClaw 并行、对接成本高不高。
于是花了两天读源码。结论:Multica 的核心价值不在发明新 Agent 能力,而在 一个干净的协作调度层 。它把 13 种 CLI 统一到一个接口下,用 Issue 做任务追溯,用 Daemon 做本地执行。设计很克制,工程水平很高。
一句话定位
Multica 不是 Agent 框架,不是 AI 模型,是一个 协作管理层 ——管的是 谁做什么、做到哪了、结果是什么 。
类比一下:Kubernetes 管容器调度,Multica 管 Agent 调度。你不关心里面跑的是什么镜像,你关心的是 调度策略 。
三层架构
Multica 由三层组成,物理分离:
| 层 | 部署位置 | 职责 |
|---|---|---|
| 用户交互层 | 用户设备 | Web UI / Desktop / iOS / CLI |
| 服务端层 | Cloud 或自托管 | REST API + WebSocket,任务调度 |
| 执行层 | 开发者本机 | Daemon 调用 Agent CLI |
关键设计: 服务端不知道 Agent 怎么执行 。它只负责调度和状态管理。实际执行完全由 Daemon 在本地完成。这种分离让 Multica 可以支持任意 CLI,不需要服务端了解每个 Agent 的 API。
)
三层架构:服务端不知道 Agent 怎么执行,只管调度和状态管理。实际执行完全由 Daemon 在本地完成。
最有价值的代码:Agent Backend 抽象
server/pkg/agent/agent.go 里定义了一个统一接口:
type Backend interface {
Execute(ctx context.Context, prompt string, opts ExecOptions) (*Session, error)
}
每个 CLI 一个实现文件,13 个 Backend 横向展开:
13 个 Backend 横向展开,每个 CLI 一个文件: claude.go / codex.go / copilot.go / openclaw.go / opencode.go / cursor.go / gemini.go / hermes.go / kimi.go / kiro.go / pi.go / antigravity.go / codebuddy.go 。
每个 Backend 实现同样的 Execute 方法,但内部处理各自的 CLI 调用差异。比如:
- •
claude.go处理 Session 恢复和 thinking level - •
codex.go处理 sandbox 策略和 multi-agent - •
openclaw.go有 local/gateway 模式切换 - •
cursor.go处理 Unix/Windows 调用差异
新增一个 CLI 只需加一个文件,实现接口,完事。这就是 插件化 的正确姿势。
Daemon 怎么跑任务
Daemon 是运行在开发者本机的后台进程,五个步骤循环执行:
- 1. 检测 :扫描 PATH 上的 claude/codex/copilot 等 CLI
- 2. 注册 :设备名、可用 CLI、版本上报到服务端
- 3. 轮询 :每 3s 向服务端 claim 任务
- 4. 执行 :调用对应 CLI 处理 Issue
- 5. 上报 :WebSocket 流式推送执行进度
任务执行的生命周期
)
Issue 从创建到完成:入队 → 认领 → 执行 → 收尾,三层 watchdog 防止任务卡死。
几个工程细节值得注意:
EmptyClaimCache — 当某 runtime 没有待处理任务时缓存这个状态,Daemon 轮询时跳过 DB 查询。一个小优化,但在多 workspace 场景下大幅减少空查询。
双层 Watchdog — IdleWatchdog 监控 Agent 总体空闲(30 分钟), ToolWatchdog 监控单个工具调用(2 小时)。分开设计是因为 Agent 可能整体在工作,但某个工具卡死了。
Orphan Recovery — Daemon 重启时主动上报:之前在跑的任务挂了,服务端立即标记失败并触发重试。不用等心跳超时(75s + 任务超时 2.5h)。
Prompt 不是直接丢给 Agent
Multica 不会把 Issue 描述直接丢给 CLI。它有 5 种结构化的 Prompt 构建器:
| 任务类型 | 构建器 | 场景 |
|---|---|---|
| 标准分配 | BuildPrompt() |
multica issue get 理解任务 |
| 评论触发 | buildCommentPrompt() |
嵌入触发评论 + 回复指令 |
| 聊天 | buildChatPrompt() |
嵌入用户消息 + 附件列表 |
| 自动驾驶 | buildAutopilotPrompt() |
嵌入 Autopilot 指令 |
| 快速创建 | buildQuickCreatePrompt() |
结构化 Issue 创建 |
评论触发的 Prompt 特别精细:区分触发者是人类还是另一个 Agent。如果是 Agent-to-Agent,加入 沉默是金 规则避免 ping-pong 循环。
Squad 委派与防循环
Squad = 1 个领导 Agent + N 个成员(Agent 或人类)。分配给 Squad 的任务先到领导,领导有两条路:自己干,或者委派给某个成员 Agent。如果领导判断不需要行动,调用 multica squad activity no_action 。
防循环机制 :同一 Agent 在同一 Issue 上已有 pending task 时,新的 @提及被静默跳过。这条规则在 HasPendingTaskForIssueAndAgent 查询里实现,简单但有效。
@提及系统精确到 UUID,四种类型各有效果:
| 类型 | 格式 | 效果 |
|---|---|---|
agent |
[@Name](mention://agent/<uuid>) |
触发该 Agent 执行 |
squad |
[@Name](mention://squad/<uuid>) |
触发 Squad 领导 |
member |
[@Name](mention://member/<uuid>) |
仅渲染链接,不触发 |
issue |
[@Name](mention://issue/<uuid>) |
仅渲染链接 |
@all |
[@all](mention://all/all) |
广播,抑制 assignee 自动触发 |
用 UUID 而不是名字,避免了重名问题。链接解析靠正则 mention://(member|agent|squad|issue|all)/([0-9a-fA-F-]+|all) ,名字混进去直接失效。
内置 Skill 系统:源码追踪
Multica 在服务端编译时嵌入了 7 个内置技能:
| 技能 | 用途 |
|---|---|
multica-autopilots |
自动驾驶使用指南 |
multica-creating-agents |
创建新 Agent |
multica-mentioning |
@提及机制详解 |
multica-projects-and-resources |
项目和资源管理 |
multica-runtimes-and-repos |
运行时和仓库配置 |
multica-skill-importing |
技能导入流程 |
multica-squads |
小队委派机制 |
multica-working-on-issues |
Issue 工作流 |
这些技能是 source-traced contracts ——每个声明都标注了对应的 Go 源码位置。比如 multica-mentioning 技能里写了 util.MentionRe in server/internal/util/mention.go ,代码变了技能文档也要同步。还有一个 Go 行为测试 TestMentioningSkillTeachesTheParserContract 来验证技能文档和代码一致。
✏️ 这个思路很值得借鉴
技能文档和代码双向绑定。文档不是 写了就忘 的说明书,而是跟代码一起演化的活文档。
前端架构:严格的包边界
前端是 Monorepo,代码量 158K 行 TS/TSX(不含测试)。包结构三层分离:
- •
packages/core/— 无头业务逻辑(零 react-dom),包含 30+ 领域模块(api、issues、agents、squads 等) - •
packages/ui/— 原子组件(零业务逻辑) - •
packages/views/— 业务页面(零 next/* / react-router)
硬规则 :服务端数据只能用 TanStack Query 管理,WebSocket 事件只做 query invalidation, 禁止 直接写 store。客户端 UI 状态用 Zustand, 禁止 复制服务端数据到 Zustand。
还有一条 Parse, don't cast 规则——所有 API 响应通过 zod schema 解析 + fallback。因为 Electron 桌面端更新滞后于服务端,API 响应可能漂移。不加 fallback 就崩。这条规则来自 3 次真实事故。
实战体验:自托管部署
)
自托管后的首页。看板视图,Issue 卡片上有 Agent 头像。
)
Issue 详情页:Agent 被 @ 提及后自动执行,在评论区报告进度。注意右侧 进行中 状态和 紧急 优先级。
)
我的 Issue 视图。右上角运行时菜单有红点告警——实际部署时确实会碰到 Daemon 状态问题。
)
运行时管理页面。可以看到 Daemon 上线状态、可用 CLI 列表、版本号。
)
Issue 生命周期视图:todo → in_progress → done 的完整流转。
)
Autopilot 自动驾驶配置页面。可以设置 Cron 定时触发或 Webhook 触发。
跑了 3 个真实 Issue,Agent 在评论区主动汇报进度,完成后自动更新状态。整个流程比 tmux 分屏 + 手动复制 prompt 好太多。
我的选择:OpenClaw + Multica 双轨并行
读完源码后,我决定把 Multica 和 OpenClaw 并行使用,而不是替换。这是我个人实践中的选择,供参考。
)
Multica 做主控管调度,OpenClaw 作为 Backend 节点保留日常助手能力,Claude Code 做纯编码。两者共享同一个 Git 库和工作区。
为什么不直接换掉 OpenClaw
两个顾虑:
- 1.
运维惯性— OpenClaw 已有自动化部署、更新脚本、配置推送。换一个工具意味着重建这套基建。 - 2.
生存风险— Multica 没有大团队背书,开源项目随时可能停更。OpenClaw 社区活跃度高,一直在打补丁升级。
为什么要引入 Multica
OpenClaw 的结构性短板在于它是 对话驱动 而非 任务驱动 :
- • Session 用随机 UUID 命名,无法自定义,找不到之前的对话
- • 没有
任务概念,只有对话,中断了不知道进度到哪 - • 不适合
提交一个有明确交付物的任务这种工程场景
Multica 恰好补上这块:Issue 就是任务,有状态、有追溯、有结果。
分工方案
| 场景 | 用什么 |
|---|---|
| 工程任务、Issue 追踪、多 Agent 编码 | Multica |
| 日常记忆、生活管理、多渠道通信 | OpenClaw |
| Claude Code 纯编码任务 | Multica 直接调度 |
| 移动端随手记、微信通知 | OpenClaw PWA |
💡 对接成本很低
Multica 的 pkg/agent/openclaw.go 已有完整实现。 OpenclawMode 字段支持 local (本地内嵌)和 gateway (网关路由)两种模式。注册 OpenClaw 为 runtime,分配 Issue 给它执行就行。
当然这是我个人的方案,还在验证中。如果你也在用 OpenClaw 或者其他 Agent CLI,可以参考这个思路。
工程质量评价
注释质量极高
Go 代码的注释不是 这行做什么 ,而是 为什么这样做 。每个 const 有设计理由,每个 watchdog 引用了 issue 编号(MUL-XXXX),每个 bug fix 在注释中解释根因。这是成熟团队的标志。
事故驱动改进
| 事故 | 改进 |
|---|---|
| #1661 | UUID 解析三路分离(混合输入 / 纯 UUID / 可信传递) |
| #2143/2147/2192 | API 响应防御性编程 + zod fallback |
| MUL-2300 | IdleWatchdog 从 5min 调到 30min |
| MUL-3064 | ToolWatchdog 独立于 IdleWatchdog |
每次事故都有对应的代码改进和注释记录。不是 改了就忘 ,而是 改了就记下来 ,让后来的人理解为什么这么写。
代码规模
Go 125K 行 + TS 158K 行,不含测试。测试文件单独算的话再翻一倍。这个体量已经不是 玩具项目 了,是一个认真的工程。
局限性
Daemon 轮询有浪费
默认 3s 轮询,虽然有 EmptyClaimCache 优化,但在多 workspace 场景下仍然产生大量空请求。WebSocket push 模式会更好,但实现复杂度也更高。
内置技能硬编码
7 个内置技能编译时嵌入 Go 二进制,更新需要重新编译部署。虽然保证了版本一致性,但迭代不够灵活。
PostgreSQL 17 运维成本
自托管需要维护一个 PostgreSQL 17 + pgvector 实例。对小团队来说不是零成本。
没有预算控制
每个 Agent CLI 自己处理 API 账单,Multica 不在 UI 层展示 这个 Issue 花了多少钱 。需要精细成本控制的话,得去各自提供商后台查。
部署
自托管只需两步:
curl -fsSL https://raw.githubusercontent.com/multica-ai/multica/main/scripts/install.sh | bash -s -- --with-server
multica setup self-host
需要 Docker + Docker Compose。默认拉 GHCR 上的官方镜像。打开 http://localhost:3000 就能用。
总结
Multica 值得关注的原因不是它 功能多 ,而是它 设计干净 :
- •
Backend 抽象层统一 13 种 CLI,新增一个只需一个文件 - •
Issue 做任务追溯,Agent 执行有状态、有记录、可恢复 - •
Daemon 本地执行,代码不上传,隐私可控 - •
Prompt 结构化构建,不是把需求直接丢给 Agent - •
源码追踪技能,文档和代码双向绑定
对于已经在用多个 AI CLI 但苦于协作靠复制粘贴的团队,Multica 值得一试。
GitHub: multica-ai/multica [1] · Apache 2.0 · 36K+ Star
引用链接
[1] multica-ai/multica: https://github.com/multica-ai/multica
继续滑动看下一个
极客工具 XTool
向上滑动看下一个